// @author Maciej Chałapuk (maciej@chalapuk.pl)
// vim: ts=2 sw=2 expandtab

#include "bitcount.hpp"

#include <boost/test/unit_test.hpp>
#include <boost/test/test_case_template.hpp>
#include <boost/mpl/list.hpp>
#include <boost/mpl/insert_range.hpp>


BOOST_AUTO_TEST_SUITE( bitcount )


typedef boost::mpl::list<
    experiment::bitcount::parallel
    > bitcount_types;

typedef boost::mpl::list<int8_t, int16_t, int32_t, int64_t>
  sint_types;
typedef boost::mpl::list<uint8_t, uint16_t, uint32_t, uint64_t>
  uint_types;
typedef boost::mpl::insert_range<
    sint_types, boost::mpl::end<sint_types>::type, uint_types>::type
  int_types;


template <class int_type>
struct test {
  test(int_type arg, size_t expected)
    : m_arg(arg), m_expected(expected) {
  }
  template <class counter_type>
  void operator() (counter_type) {
    counter_type count;
    BOOST_CHECK_EQUAL(count(m_arg), m_expected);
  }
  int_type m_arg;
  size_t m_expected;
};


BOOST_AUTO_TEST_CASE_TEMPLATE( full, uint_t, uint_types ) {
  boost::mpl::for_each<bitcount_types>(
      test<uint_t>(static_cast<uint_t>(-1), sizeof(uint_t)*8)
      );
}

BOOST_AUTO_TEST_CASE_TEMPLATE( half, int_t, int_types ) {
  size_t halfsize = sizeof(int_t)*4;
  boost::mpl::for_each<bitcount_types>(
      test<int_t>((~static_cast<int_t>(0)) << halfsize, halfsize)
      );
}

BOOST_AUTO_TEST_CASE_TEMPLATE( first, uint_t, uint_types ) {
  boost::mpl::for_each<bitcount_types>(
      test<uint_t>((static_cast<uint_t>(-1) >> 1) + 1u, 1)
      );
}

BOOST_AUTO_TEST_CASE_TEMPLATE( last, int_t, int_types ) {
  boost::mpl::for_each<bitcount_types>(
      test<int_t>(static_cast<int_t>(1), 1)
      );
}


BOOST_AUTO_TEST_SUITE_END()


